#pragma once
#include <iostream>
#include <thread>
#include <atomic>

namespace detail
{
    size_t *thread_id()
    {
        static thread_local size_t thread_id = -1u;
        return &thread_id;
    }
}

template <typename Task, template <typename> class Queue>
class Worker
{
public:
    Worker(size_t queue_size) : is_running(true), _queue(queue_size)
    {
    }

    Worker(Worker &&w) noexcept
    {
        *this = std::move(w);
    }

    Worker &operator=(Worker &&w) noexcept
    {
        if (this != &w)
        {
            _queue = std::move(w._queue);
            is_running = w.is_running.load();
            _worker = std::move(w._worker);
        }
        return *this;
    }

    void start(size_t id, Worker *steal_donor)
    {
        _worker = std::thread(&Worker<Task, Queue>::entry, this, id, steal_donor);
    }

    void stop()
    {
        is_running.store(false, std::memory_order_relaxed);
        _worker.join();
    }

    template <typename Handler>
    bool post(Handler &&handler)
    {
        // std::cout << "线程" << "插入任务" << std::endl;
        return _queue.push(std::forward<Handler>(handler));
    }

    bool steal(Task &task)
    {
        return _queue.pop(task);
    }

    static size_t getWorkerIdForCurrentThread()
    {
        return *detail::thread_id();
    }

    ~Worker() {}

private:
    void entry(size_t id, Worker *steal_donor)
    {
        *detail::thread_id() = id;

        Task handler;
        // std::cout << "线程" << id << "执行任务" << std::endl;
        while (is_running.load(std::memory_order_relaxed))
        {
            // bool ret = _queue.pop(handler) || steal_donor->steal(handler);
            bool ret = _queue.pop(handler);
            // std::cout << ret << std::endl;
            if (ret)
            {
                try
                {
                    // std::cout << "线程" << id << "执行任务" << std::endl;
                    handler();
                }
                catch (...)
                {
                    // std::cout << "线程" << id << "执行任务异常" << std::endl;
                    // suppress all exceptions
                }
            }
            else
            {
                std::this_thread::sleep_for(std::chrono::milliseconds(1));
            }
        }
    }

    std::atomic<bool> is_running;
    Queue<Task> _queue;
    std::thread _worker;
};